﻿using System;

namespace FortuneUniverse.Fortune.Algorithms
{
  public struct Vector2 : IEquatable<Vector2>
  {
    public float x;
    public float y;
    private static readonly Vector2 zeroVector = new Vector2(0.0f, 0.0f);
    private static readonly Vector2 oneVector = new Vector2(1f, 1f);
    private static readonly Vector2 upVector = new Vector2(0.0f, 1f);
    private static readonly Vector2 downVector = new Vector2(0.0f, -1f);
    private static readonly Vector2 leftVector = new Vector2(-1f, 0.0f);
    private static readonly Vector2 rightVector = new Vector2(1f, 0.0f);
    private static readonly Vector2 positiveInfinityVector = new Vector2(float.PositiveInfinity, float.PositiveInfinity);
    private static readonly Vector2 negativeInfinityVector = new Vector2(float.NegativeInfinity, float.NegativeInfinity);
    public const float kEpsilon = 1E-05f;
    public const float kEpsilonNormalSqrt = 1E-15f;

    public Vector2(float x, float y)
    {
      this.x = x;
      this.y = y;
    }

    public float this[int index]
    {
      get
      {
        float num;
        if (index != 0)
        {
          if (index != 1)
            throw new IndexOutOfRangeException("Invalid Vector2 index!");
          num = this.y;
        }
        else
          num = this.x;
        return num;
      }
      set
      {
        if (index != 0)
        {
          if (index != 1)
            throw new IndexOutOfRangeException("Invalid Vector2 index!");
          this.y = value;
        }
        else
          this.x = value;
      }
    }

    public void Set(float newX, float newY)
    {
      this.x = newX;
      this.y = newY;
    }

    public static Vector2 Lerp(Vector2 a, Vector2 b, float t)
    {
      t = Mathf.Clamp01(t);
      return new Vector2(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t);
    }

    public static Vector2 LerpUnclamped(Vector2 a, Vector2 b, float t) => new Vector2(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t);

    public static Vector2 MoveTowards(
      Vector2 current,
      Vector2 target,
      float maxDistanceDelta)
    {
      Vector2 vector2 = target - current;
      float magnitude = vector2.magnitude;
      return (double) magnitude <= (double) maxDistanceDelta || (double) magnitude == 0.0 ? target : current + vector2 / magnitude * maxDistanceDelta;
    }

    public static Vector2 Scale(Vector2 a, Vector2 b) => new Vector2(a.x * b.x, a.y * b.y);

    public void Scale(Vector2 scale)
    {
      this.x *= scale.x;
      this.y *= scale.y;
    }

    public void Normalize()
    {
      float magnitude = this.magnitude;
      if ((double) magnitude > 9.99999974737875E-06)
        this = this / magnitude;
      else
        this = Vector2.zero;
    }

    public Vector2 normalized
    {
      get
      {
        Vector2 vector2 = new Vector2(this.x, this.y);
        vector2.Normalize();
        return vector2;
      }
    }

    public override string ToString() => string.Format("({0:F1}, {1:F1})", new object[2]
    {
      (object) this.x,
      (object) this.y
    });

    public string ToString(string format) => string.Format("({0}, {1})", new object[2]
    {
      (object) this.x.ToString(format),
      (object) this.y.ToString(format)
    });

    public override int GetHashCode() => this.x.GetHashCode() ^ this.y.GetHashCode() << 2;

    public override bool Equals(object other) => other is Vector2 other1 && this.Equals(other1);

    public bool Equals(Vector2 other) => this.x.Equals(other.x) && this.y.Equals(other.y);

    public static Vector2 Reflect(Vector2 inDirection, Vector2 inNormal) => -2f * Vector2.Dot(inNormal, inDirection) * inNormal + inDirection;

    public static Vector2 Perpendicular(Vector2 inDirection) => new Vector2(-inDirection.y, inDirection.x);

    public static float Dot(Vector2 lhs, Vector2 rhs) => (float) ((double) lhs.x * (double) rhs.x + (double) lhs.y * (double) rhs.y);

    public float magnitude => Mathf.Sqrt((float) ((double) this.x * (double) this.x + (double) this.y * (double) this.y));

    public float sqrMagnitude => (float) ((double) this.x * (double) this.x + (double) this.y * (double) this.y);

    public static float Angle(Vector2 from, Vector2 to)
    {
      float num = Mathf.Sqrt(from.sqrMagnitude * to.sqrMagnitude);
      return (double) num >= 1.00000000362749E-15 ? Mathf.Acos(Mathf.Clamp(Vector2.Dot(from, to) / num, -1f, 1f)) * 57.29578f : 0.0f;
    }

    public static float SignedAngle(Vector2 from, Vector2 to) => Vector2.Angle(from, to) * Mathf.Sign((float) ((double) from.x * (double) to.y - (double) from.y * (double) to.x));

    public static float Distance(Vector2 a, Vector2 b) => (a - b).magnitude;

    public static Vector2 ClampMagnitude(Vector2 vector, float maxLength) => (double) vector.sqrMagnitude <= (double) maxLength * (double) maxLength ? vector : vector.normalized * maxLength;

    public static float SqrMagnitude(Vector2 a) => (float) ((double) a.x * (double) a.x + (double) a.y * (double) a.y);

    public float SqrMagnitude() => (float) ((double) this.x * (double) this.x + (double) this.y * (double) this.y);

    public static Vector2 Min(Vector2 lhs, Vector2 rhs) => new Vector2(Mathf.Min(lhs.x, rhs.x), Mathf.Min(lhs.y, rhs.y));

    public static Vector2 Max(Vector2 lhs, Vector2 rhs) => new Vector2(Mathf.Max(lhs.x, rhs.x), Mathf.Max(lhs.y, rhs.y));

    public static Vector2 operator +(Vector2 a, Vector2 b) => new Vector2(a.x + b.x, a.y + b.y);

    public static Vector2 operator -(Vector2 a, Vector2 b) => new Vector2(a.x - b.x, a.y - b.y);

    public static Vector2 operator *(Vector2 a, Vector2 b) => new Vector2(a.x * b.x, a.y * b.y);

    public static Vector2 operator /(Vector2 a, Vector2 b) => new Vector2(a.x / b.x, a.y / b.y);

    public static Vector2 operator -(Vector2 a) => new Vector2(-a.x, -a.y);

    public static Vector2 operator *(Vector2 a, float d) => new Vector2(a.x * d, a.y * d);

    public static Vector2 operator *(float d, Vector2 a) => new Vector2(a.x * d, a.y * d);

    public static Vector2 operator /(Vector2 a, float d) => new Vector2(a.x / d, a.y / d);

    public static bool operator ==(Vector2 lhs, Vector2 rhs) => (double) (lhs - rhs).sqrMagnitude < 9.99999943962493E-11;

    public static bool operator !=(Vector2 lhs, Vector2 rhs) => !(lhs == rhs);

    public static implicit operator Vector2(Vector3 v) => new Vector2(v.x, v.y);

    public static implicit operator Vector3(Vector2 v) => new Vector3(v.x, v.y, 0.0f);

    public static Vector2 zero => Vector2.zeroVector;

    public static Vector2 one => Vector2.oneVector;

    public static Vector2 up => Vector2.upVector;

    public static Vector2 down => Vector2.downVector;

    public static Vector2 left => Vector2.leftVector;

    public static Vector2 right => Vector2.rightVector;

    public static Vector2 positiveInfinity => Vector2.positiveInfinityVector;

    public static Vector2 negativeInfinity => Vector2.negativeInfinityVector;
  }
}
